package com.authentications.service;

import com.authentications.info.Oauth2AcValue;
import com.authentications.primary.DefaultUserDetailsService;
import com.authentications.primary.authent.AuthorizationServer;
import com.authentications.primary.authent.MyTokenEnhancer;
import com.authentications.utils.SpringContextUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;
import org.springframework.security.oauth2.provider.code.JdbcAuthorizationCodeServices;
import org.springframework.security.oauth2.provider.token.*;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;

import javax.sql.DataSource;
import java.util.ArrayList;
import java.util.List;

/**
 * @ClassName AuthenticationAcServiceAutoConfiguration
 * @Author xiezhuocai
 * @Description TODO
 * @Date 2021/12/15 9:22
 */
@Configuration
@ConditionalOnWebApplication
@EnableAuthorizationServer
@EnableConfigurationProperties(Oauth2AcValue.class)
public class AuthenticationAcServiceAutoConfiguration {

    @Autowired
    private Oauth2AcValue oauth2AcValue;

    @Autowired
    private ClientDetailsService detailsService;

    @Bean
    public SpringContextUtils springContextUtils() {
        return new SpringContextUtils();
    }


    @Bean
    public TokenStore tokenStore(){
        return new JwtTokenStore(accessTokenConverter());//策略模式使用Jwt来存存储令牌
    }


    @Bean
    public JwtAccessTokenConverter accessTokenConverter(){
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        if (oauth2AcValue.getSigning_key() != null) converter.setSigningKey(oauth2AcValue.getSigning_key());
        if (oauth2AcValue.getSigning_key() == null) converter.setSigningKey("admin");
        return converter;
    }

    //密码编码器
    @Bean
    public PasswordEncoder passwordEncoder(){
        //return NoOpPasswordEncoder.getInstance();//不加密
        return new BCryptPasswordEncoder(); //BCrypt加密
    }

    @Bean
    public MyTokenEnhancer myTokenEnhancer() {
        return new MyTokenEnhancer();
    }

    @Bean
    @ConditionalOnMissingBean(UserDetailsService.class)
    public DefaultUserDetailsService userDetailsService(){
        return new DefaultUserDetailsService();
    }

    @Bean
    @ConditionalOnMissingBean(AuthorizationServer.class)
    public AuthorizationServer authorizationServer(){
        return new AuthorizationServer();
    }

    @Bean
    public ClientDetailsService detailsService(DataSource dataSource){
        ClientDetailsService detailsService = new JdbcClientDetailsService(dataSource);
        ((JdbcClientDetailsService)detailsService).setPasswordEncoder(passwordEncoder());
        return detailsService;
    }

    //令牌管理服务
    @Bean
    public AuthorizationServerTokenServices tokenServices() {
        DefaultTokenServices services = new DefaultTokenServices();
        services.setClientDetailsService(detailsService);//客户端详情服务
        services.setSupportRefreshToken(true);//支持刷新令牌
        services.setTokenStore(tokenStore());//令牌策略
        //令牌增强
        TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
        List<TokenEnhancer> enhancers = new ArrayList<>();
        enhancers.add(new MyTokenEnhancer());
        enhancers.add(accessTokenConverter());
        tokenEnhancerChain.setTokenEnhancers(enhancers);
        services.setTokenEnhancer(tokenEnhancerChain);

        services.setAccessTokenValiditySeconds(7200);//令牌默认有效期2小时
        services.setRefreshTokenValiditySeconds(259200);//刷新令牌默认有效期3天
        return services;
    }

    //授权码模式的授权码如何存取,暂时采用内存
    /*@Bean
    public AuthorizationCodeServices authorizationCodeServices(){
        return new InMemoryAuthorizationCodeServices();
    }*/
    //数据库存取授权码
    @Bean
    public AuthorizationCodeServices authorizationCodeServices(DataSource dataSource){
        return new JdbcAuthorizationCodeServices(dataSource);
    }

}
